#ifndef __DCCFXPLAYER_H_
#define __DCCFXPLAYER_H_

#include <stdint.h>
#include <stdio.h>

#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL 3 // 0:关闭, 1:错误, 2:信息, 3:数据信息
#endif

#if DEBUG_LEVEL >= 1
#define DCCFX_ERROR(fmt, ...) printf("[ERROR] " fmt, ##__VA_ARGS__)
#else
#define DCCFX_ERROR(fmt, ...) do {} while (0)
#endif

#if DEBUG_LEVEL >= 2
#define DCCFX_PRINT(fmt, ...) printf( fmt, ##__VA_ARGS__)
#else
#define DCCFX_PRINT(fmt, ...) do {} while (0)
#endif

typedef enum {
    RUNSTATE_K_STOP = 0,
    RUNSTATE_K_READ_ZONE_PARAS,
    RUNSTATE_K_READ_FRAME,
    RUNSTATE_K_SEND_FRAME,
    RUNSTATE_K_WAIT_FRAME_END,
    RUNSTATE_K_ZONE_END,
    RUNSTATE_K_ERR
} run_state_k;

typedef enum {
    TIMEUNIT_K_MS = 0,
    TIMEUNIT_K_S,
    TIMEUNIT_K_MIN
} time_unit_k;

typedef enum {
    LOOPTYPE_K_INVALID = 0,
    LOOPTYPE_K_INFINITE,
    LOOPTYPE_K_MULTIPLE,
    LOOPTYPE_K_SINGLE
} loop_type_k;

typedef enum {
    ENDACTION_K_JUMP_NEXT_ZONE = 0,
    ENDACTION_K_KEEP_END_FRAME,
    ENDACTION_K_CLOSE_LAMP
} end_action_k;

struct dccfxplayer {
    uint8_t runing;
    run_state_k curr_state;
    uint8_t * p_read_buffer;
    uint32_t read_addr_curr;

    uint8_t curr_zone;
    uint16_t channel_count;
    uint16_t led_count;
    uint8_t enabled;

    uint16_t frame_count;
    uint16_t curr_frame;
    uint16_t frame_size;
    uint16_t frame_time_target;
    uint16_t frame_curr_time;
    time_unit_k frame_time_unit;
    uint8_t frame_time_type;

    uint16_t preset_time_values[5];
    time_unit_k preset_time_units[5];
    uint8_t play_speed;
    loop_type_k loop_type;
    uint8_t loop_count_max;
    uint8_t curr_loop;
    end_action_k loop_end_action;

    /* Read the running parameters of zone effect. If successful, return 0 */
    int (*cb_read_zone) (struct dccfxplayer *pl);
    /* Read a frame of effect data, including the frame time. If successful, return 0 */
    int (*cb_read_frame) (struct dccfxplayer *pl);
    /* Send frame effect data */
    void (*cb_send_frame) (struct dccfxplayer *pl);
    /* Zone effect playback ends, do finishing work. For example, closing the effect file */
    void (*cb_end_work) (void);
    /* Immediately turn off all leds. */
    void (*cb_turn_off) (void);

    void (*cb_run_err) (void);
};


void dccfxplayer_state_poll (struct dccfxplayer *pl);

void dccfxplayer_time_tick (struct dccfxplayer *pl);

void dccfxplayer_init(struct dccfxplayer *pl,
                      uint8_t *buffer,
                      int (*read_zone)(struct dccfxplayer *),
                      int (*read_frame)(struct dccfxplayer *),
                      void (*send_frame)(struct dccfxplayer *),
                      void (*end_work)(void),
                      void (*turn_off)(void),
                      void (*run_err)(void),
                      uint8_t speed);

void dccfxplayer_start(struct dccfxplayer *pl, uint8_t zone);

void dccfxplayer_stop(struct dccfxplayer *pl);

uint32_t scale_frame_time(uint32_t frame_time, uint8_t play_speed);

#endif
